package cn.woblog.android.downloader.service;

import java.util.List;
import java.util.Map;

import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import cn.woblog.android.downloader.db.DBController;
import cn.woblog.android.downloader.domain.DownloadInfo;
import cn.woblog.android.downloader.domain.DownloadStatus;
import cn.woblog.android.downloader.observable.DataChanger;
import cn.woblog.android.downloader.thread.DownloadTask;
import cn.woblog.android.downloader.utils.Consts;
import cn.woblog.android.downloader.utils.MyLog;

public class DownloadService extends Service {

	private String id;
	private DataChanger dataChanger;
	private Handler handler = new Handler() {
		public void handleMessage(android.os.Message msg) {
			switch (msg.what) {
			case Consts.MSG_DOWNLOAD_COMPLETE:
				checkNext((String) msg.obj);
				break;
			case Consts.MSG_CHECK_NEXT:
				startNext();
				break;

			default:
				break;
			}
		};
	};
	private DBController dbController;

	@Override
	public void onCreate() {
		dataChanger = DataChanger.getInstance(getApplicationContext());
		dbController = DBController.getInstance(getApplicationContext());
		MyLog.d("start download service");
		queryDownloadUnFinishHistory();
		super.onCreate();
	}

	private void queryDownloadUnFinishHistory() {
		List<DownloadInfo> queryAll = dbController.queryAll();
		if (queryAll != null && queryAll.size() > 0) {
			for (DownloadInfo downloadInfo : queryAll) {
				if (downloadInfo != null) {
					switch (downloadInfo.getStatus()) {
					case DOWNLOADING:
						MyLog.d("recover downloading " + downloadInfo.getId());
						add(downloadInfo);
						break;
					case PAUSE:
						dataChanger.addDownload(downloadInfo.getId(),
								downloadInfo);
					case DONE:
						MyLog.d("recover pause|done " + downloadInfo.getId());
						dataChanger.addNotifiy(downloadInfo);
						dataChanger.startNotifyLooper();
						break;

					default:
						break;
					}
				}
			}

			for (DownloadInfo downloadInfo : queryAll) {
				if (downloadInfo != null) {
					switch (downloadInfo.getStatus()) {
					case WAITING:
						MyLog.d("recover WAITING " + downloadInfo.getId());
						add(downloadInfo);
						break;
					default:
						break;
					}
				}
			}
		}
	}

	protected void checkNext(String id) {
		MyLog.d("check next");
		dataChanger.removeDownloadTask(id);
		startNext();
	}

	private void startNext() {
		if (dataChanger.getDownloadTaskSize() >= Consts.MAX_TASK_COUNT) {
		} else {
			DownloadInfo info = dataChanger.getNextDownloadInfo();
			if (info != null) {
				startDownload(info);
			}
		}
	}

	@Override
	public IBinder onBind(Intent intent) {
		return null;
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		if (intent != null && intent.getExtras() != null) {
			DownloadStatus status = DownloadStatus.valueOf(intent
					.getStringExtra(Consts.KEY_ACTION));
			switch (status) {
			case ADD:
				DownloadInfo info = (DownloadInfo) intent
						.getSerializableExtra(Consts.KEY_DATA);
				add(info);
				break;
			case PAUSE:
				id = intent.getStringExtra(Consts.KEY_DATA);
				pause(id);
				break;
			case RESUME:
				id = intent.getStringExtra(Consts.KEY_DATA);
				resume(id);
				break;
			case DELETE:
				id = intent.getStringExtra(Consts.KEY_DATA);
				delete(id);
				break;

			default:
				break;
			}
		}
		return super.onStartCommand(intent, flags, startId);
	}

	public void add(DownloadInfo info) {
		if (dataChanger.getDownloadTaskSize() >= Consts.MAX_TASK_COUNT) {
			info.setStatus(DownloadStatus.WAITING);
			dataChanger.addDownload(info.getId(), info);
			dataChanger.startNotifyLooper();
			dataChanger.addNotifiy(info);
			dbController.newOrUpdate(info);
		} else {
			startDownload(info);
		}

	}

	private void startDownload(DownloadInfo info) {
		info.setStatus(DownloadStatus.DOWNLOADING);
		DownloadTask task = new DownloadTask(getApplicationContext(), info,
				handler);
		task.start();
		dataChanger.addTask(info.getId(), task);
		dataChanger.addDownload(info.getId(), info);
		dataChanger.addNotifiy(info);
		dbController.newOrUpdate(info);
		dataChanger.startNotifyLooper();
	}

	public void pause(String id) {
		DownloadTask task = dataChanger.getDownloadTask(id);
		if (task != null) {
			dataChanger.removeDownloadTask(id);
			task.pause(true);
			dataChanger.addPauseTask(id, task);
		}
	}

	public void resume(String id) {
		dataChanger.startNotifyLooper();
		if (dataChanger.getDownloadTaskSize() >= Consts.MAX_TASK_COUNT) {
			DownloadInfo info = dataChanger.getDownload(id);
			if (info != null) {
				info.setStatus(DownloadStatus.WAITING);
				dataChanger.addNotifiy(info);
				dbController.newOrUpdate(info);
			}
		} else {
			DownloadTask task = dataChanger.getPauseTask(id);
			if (task != null) {
				dataChanger.removePauseTask(id);
				task.pause(false);
				dataChanger.addTask(id, task);
				synchronized (task) {
					task.notifyAll();
				}
			} else {
				DownloadInfo download = dataChanger.getDownload(id);
				if (download != null) {
					add(download);
				}
			}
		}

		dataChanger.startNotifyLooper();
	}

	public void deleteAll() {
		dataChanger.startNotifyLooper();
		Map<String, DownloadTask> task = dataChanger.getDownloadTasks();
		if (task != null && task.size() > 0) {
			for (Map.Entry<String, DownloadTask> item : task.entrySet()) {
				DownloadTask iTask = item.getValue();
				if (iTask != null) {
					iTask.stop();
				}
			}

		}
		dataChanger.removeNotifiy(id);
		dataChanger.removeDownloadTask(id);
		dbController.deleteAll();
	}

	public void delete(String id) {
		DownloadTask task = dataChanger.getDownloadTask(id);
		if (task != null) {
			task.stop();
		}
		dataChanger.notifyDeleteDataById(id);
		dataChanger.removeNotifiy(id);
		dataChanger.removeDownloadTask(id);
		dbController.deleteById(id);
	}
}
